Docly Developers
Knowledge base Clarification Recommended

Use AVIF and WebP image formats

In shortYou keep uploading JPEG/PNG as before; Docly converts on serving, and the file extension on the display name in the image URL decides the output format (…/1200x800x0/produkt.webp ⇒ WebP). WebP has universal browser support, so <img src="….webp"> is enough on its own. AVIF must sit inside a <picture> with WebP/JPEG fallback, because Docly does not negotiate format via the Accept header — without a fallback, visitors without AVIF support see nothing. A safe site-wide default is defaultFormat: webp in #/images.json; avoid avif as a global default. All of this concerns images a browser renders: og:image and other <meta> share images must still be JPEG or PNG, because a meta tag carries one URL with no <picture> fallback and the social scrapers do not reliably read WebP.
Applies to Hash templatesImages
  1. What you'll see

    You want smaller image files and a better performance score. AVIF and WebP produce noticeably smaller files than JPEG/PNG at the same perceived quality, which helps Core Web Vitals and the LCP of image-heavy pages. The question that follows is a markup one:

    <img src="….avif">

    Should the new formats be requested with a plain <img>, or does something more need to wrap them? Getting this wrong with AVIF does not throw an error in your own browser — it silently breaks the image for every visitor whose browser cannot decode AVIF.

  2. What's actually happening

    You still upload JPEG/PNG. You do not pre-convert anything. Docly converts a scaled copy of the image on serving, on demand, and the output format is chosen solely from the file extension of the display name in the image URL. So …/1200x800x0/produkt.webp is served as WebP, and …/1200x800x0/produkt.avif is served as AVIF. The extensions that steer the format are .jpg, .jpeg, .png, .webp and .avif. .gif and .svg get no conversion.

    WebP alone → <img> is enough. WebP has universal browser support, so a single <img src="….webp"> needs no fallback.

    AVIF → <picture> is required, not overkill. Docly picks the image format only from the extension in the URL. There is no Accept-header negotiation. An <img src="….avif"> therefore delivers AVIF to everyone — including browsers that cannot display it, where the image simply disappears. With <picture> it is the browser, not the server, that chooses: it takes the first <source> with a type it supports. That is the only mechanism that gives AVIF safely in Docly today.

  3. What to do

    1. Simple variant — WebP, no fallback needed. WebP support is universal, so a plain <img> with a .webp display name is all you need:

    <img src="#linkImage(f, f.Image1, 1200, 800, 0, 'produktnavn.webp')#"
         width="1200" height="800" loading="lazy" decoding="async"
         alt="#docly.htmlAttributeEncode(f.Title)#">

    2. Recommended variant — AVIF with fallback. Wrap AVIF in a <picture> with WebP and JPEG fallback. The order is significant: the browser takes the first <source> it supports, so AVIF comes before WebP:

    <picture>
      <source type="image/avif"
              srcset="#linkImage(f, f.Image1, 1200, 800, 0, 'produktnavn.avif')#">
      <source type="image/webp"
              srcset="#linkImage(f, f.Image1, 1200, 800, 0, 'produktnavn.webp')#">
      <img src="#linkImage(f, f.Image1, 1200, 800, 0, 'produktnavn.jpg')#"
           width="1200" height="800" loading="lazy" decoding="async"
           alt="#docly.htmlAttributeEncode(f.Title)#">
    </picture>

    The <img> inside <picture> is the mandatory fallback — it carries the alt, width/height and loading. Always set width/height to prevent layout shift, and use loading="lazy" on below-the-fold images — not on the top LCP image. For transparent images, the fallback must be .png, not .jpg.

    3. Site-wide default — #/images.json → defaultFormat. This applies only when the URL has no format-steering extension. Write keys in camelCase:

    {
      "defaultFormat": "webp"
    }

    webp is the safe global default. Avoid "defaultFormat": "avif" as a global default: without a <picture>, every visitor gets AVIF, and those who cannot decode it see nothing.

    4. Pitfalls.

    • Share images in <meta> tags are the exception — keep those JPEG or PNG. Everything on this page is about images a browser renders, where <picture> can supply a fallback. A <meta property="og:image"> tag carries one URL and has no fallback at all, and the social scrapers do not reliably read WebP — the preview card comes back blank while the page itself looks perfect. See Social share images must be JPEG or PNG.
    • SVG and GIF are not converted. Do not give them a .webp extension and do not wrap SVG in <picture>.
    • The size policy enforces WxHxM, not the extension. The dimensions in the URL (e.g. 1200x800x0) are what the policy checks — three formats at the same size therefore count as one size. New sizes go in allowedSizes.
    • The default open size policy does not support WebP/AVIF. Under images.sizePolicy: "open" (the default) a .webp/.avif display name is served as JPEG regardless of the extension. Set sizePolicy to auto or strict in #/images.json for the format to take effect — see Restrict and register image sizes for how to switch the policy.
    • Derived images are cached on disk per unique URL (size + format). Only the first request for a new size or format pays the encoding cost, which for AVIF is heavy.
    • 429 Too Many Requests. Docly has a guard against many concurrent scalings that only triggers on a cache miss. AVIF encoding is heavy, so warm the cache by requesting the new sizes/formats once after publishing, instead of letting the first real traffic burst hit an unwarmed cache.
    • PNG is the fallback for transparent images — both WebP and AVIF preserve alpha, but the <img> fallback must be .png so transparency survives.

    Checklist.

    • WebP only? A plain <img src="….webp"> is enough.
    • On a page, yes — but og:image and twitter:image are .jpg or .png, never WebP or AVIF.
    • AVIF? Always inside <picture> with WebP → JPEG/PNG fallback, AVIF <source> first.
    • The <img> fallback carries alt, width/height and loading.
    • Set width/height; use loading="lazy" below the fold, not on the LCP image.
    • Transparent image? Fallback is .png, not .jpg.
    • Global default in #/images.json is webp, never avif.
    • No .webp/.avif extension on SVG or GIF.
    • images.sizePolicy is auto or strict (not the default open) so WebP/AVIF actually take effect.

Last reviewed 24 Oct 2026